﻿using System;
using System.Collections.Generic;
using System.IO;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YJKArchUtils.Utils;

namespace YJKAprollDesign.FamilyCreate
{
	public class AprollFamilyManager
	{
		public AprollFamilyManager(ExternalCommandData cmdData, ElementId materialId)
		{
			this.m_Revit = cmdData;
			this.m_MaterialId = materialId;
		}

		public bool CreateAproll(double aprollMaxHeight, double aprollMinHeight, double aprollWidth, List<List<EdgeInfo>> aprollPathList, double levelOffset, ref string message)
		{
			string familiyPath = "";
			string familyName = "";
			string symbolName = "";
			if (!this.DesignAprollFamily(aprollMaxHeight, aprollMinHeight, aprollWidth, aprollPathList, ref familiyPath, ref familyName, ref symbolName, ref message))
			{
				return false;
			}
			if (!this.LoadFamiliesFile(familiyPath, ref message))
			{
				return false;
			}
			Level genLevel = this.m_Revit.Application.ActiveUIDocument.ActiveView.GenLevel;
			XYZ zero = XYZ.Zero;
			return this.CreateElement(zero, familyName, symbolName, genLevel, levelOffset, ref message);
		}

		private bool DesignAprollFamily(double aprollMaxHeight, double aprollMinHeight, double aprollWidth, List<List<EdgeInfo>> aprollPathList, ref string familyFilePath, ref string familyName, ref string symbolName, ref string message)
		{
			Document document = null;
			if (this.OpenAndActiveFamilyTemplateDocument(ref document, ref message) != null)
			{
				return false;
			}
			Transaction transaction = new Transaction(document);
			transaction.Start("create aproll family");
			if (this.CreateSweepAproll(aprollMaxHeight, aprollMinHeight, aprollWidth, aprollPathList, document, ref symbolName, ref message) != null)
			{
				if (transaction != null && transaction.HasStarted() && !transaction.HasEnded())
				{
					transaction.RollBack();
				}
				this.DocumentClose(document);
				return false;
			}
			transaction.Commit();
			if (this.SaveFamilyFile(document, ref familyFilePath, ref familyName) != null)
			{
				this.DocumentClose(document);
				return false;
			}
			return true;
		}

		private Result CreateSweepAproll(double aprollMaxHeight, double aprollMinHeight, double aprollWidth, List<List<EdgeInfo>> aprollPathList, Autodesk.Revit.DB.Document familyDocument, ref string symbolName, ref string message)
		{
			AprollFamilyCreator aprollFamilyCreator = new AprollFamilyCreator(this.m_Revit, this.m_MaterialId, familyDocument);
			Result result = aprollFamilyCreator.CreateAproll(aprollMaxHeight, aprollMinHeight, aprollWidth, aprollPathList, ref message);
			if (result != Autodesk.Revit.UI.Result.Succeeded)
			{
				return result;
			}
			result = aprollFamilyCreator.AddSymbols(ref symbolName, ref message);
			if (result != Autodesk.Revit.UI.Result.Succeeded)
			{
				return result;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result OpenAndActiveFamilyTemplateDocument(ref Document familyDocument, ref string message)
		{
			string text = AssistFunc.GetAppRootPath();
			string versionNumber = this.m_Revit.Application.Application.VersionNumber;
			text = text + "\\Templates\\" + versionNumber + "\\公制常规模型.rft";
			if (!File.Exists(text))
			{
				throw new Exception("Unsupported version");
			}
			familyDocument = this.m_Revit.Application.Application.NewFamilyDocument(text);
			if (familyDocument == null)
			{
				message = "缺少族模板.";
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private Result SaveFamilyFile(Autodesk.Revit.DB.Document familyDocument, ref string familyFilePath, ref string familyName)
		{
			int num = this.CalculateFamilyNumber();
			string tempPath = Path.GetTempPath();
			familyName = "HYAproll" + num.ToString();
			familyFilePath = tempPath + familyName + ".rfa";
			if (File.Exists(familyFilePath))
			{
				File.Delete(familyFilePath);
			}
			RevitVersionFuncs.SaveAs(familyDocument, familyFilePath);
			familyDocument.Close(true);
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private int CalculateFamilyNumber()
		{
			string text = "HYAproll";
			int length = text.Length;
			List<int> list = new List<int>();
			foreach (Element element in new FilteredElementCollector(this.m_Revit.Application.ActiveUIDocument.Document).OfClass(typeof(Family)).ToElements())
			{
				Family family = element as Family;
				if (family != null)
				{
					string name = family.Name;
					int num = name.IndexOf(text);
					if (num != -1)
					{
						string value = name.Substring(num + length, name.Length - num - length);
						int item = 0;
						try
						{
							item = Convert.ToInt32(value);
						}
						catch (Exception)
						{
							continue;
						}
						list.Add(item);
					}
				}
			}
			if (list.Count == 0)
			{
				return 1;
			}
			list.Sort();
			return list[list.Count - 1] + 1;
		}

		private void DocumentClose(Autodesk.Revit.DB.Document familyDocument)
		{
			familyDocument.Close(false);
		}

		private bool LoadFamiliesFile(string familiyPath, ref string message)
		{
			Transaction transaction = new Transaction(this.m_Revit.Application.ActiveUIDocument.Document);
			transaction.Start("load families");
			this.m_Revit.Application.ActiveUIDocument.Document.LoadFamily(familiyPath);
			transaction.Commit();
			return true;
		}

		private bool CreateElement(XYZ locationPoint, string familyName, string symbolName, Level level, double levelOffset, ref string message)
		{
			Document document = this.m_Revit.Application.ActiveUIDocument.Document;
			Transaction transaction = new Transaction(document);
			transaction.Start("create element");
			FamilySymbol familySymbolByName = this.GetFamilySymbolByName(familyName, symbolName);
			UnifiedModified.ActivateFamilySymbol(familySymbolByName);
			FamilyInstance familyInstance = document.Create.NewFamilyInstance(locationPoint, familySymbolByName, level, (Autodesk.Revit.DB.Structure.StructuralType)0);
			familyInstance.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM).Set(levelOffset);
			document.Regenerate();
			transaction.Commit();
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(document);
			ElementIntersectsElementFilter elementIntersectsElementFilter = new ElementIntersectsElementFilter(familyInstance, false);
			IList<Element> list = filteredElementCollector.WherePasses(elementIntersectsElementFilter).ToElements();
			if (list.Count > 0)
			{
				foreach (Element elementFirst in list)
				{
					this.SetJoinOrder(elementFirst, familyInstance);
				}
			}
			return true;
		}

		private void SetJoinOrder(Element elementFirst, Element elementSecond)
		{
			Document document = this.m_Revit.Application.ActiveUIDocument.Document;
			Transaction transaction = null;
			try
			{
				transaction = new Transaction(document);
				transaction.Start("SetJoinOrder");
				if (JoinGeometryUtils.AreElementsJoined(document, elementFirst, elementSecond))
				{
					if (!JoinGeometryUtils.IsCuttingElementInJoin(document, elementFirst, elementSecond))
					{
						JoinGeometryUtils.SwitchJoinOrder(document, elementFirst, elementSecond);
					}
				}
				else
				{
					JoinGeometryUtils.JoinGeometry(document, elementFirst, elementSecond);
					if (!JoinGeometryUtils.IsCuttingElementInJoin(document, elementFirst, elementSecond))
					{
						JoinGeometryUtils.SwitchJoinOrder(document, elementFirst, elementSecond);
					}
				}
				transaction.Commit();
			}
			catch (Exception)
			{
				if (transaction != null)
				{
					transaction.RollBack();
				}
			}
		}

		private FamilySymbol GetFamilySymbolByName(string familyName, string symbolName)
		{
			FamilySymbol result = null;
			foreach (Element element in new FilteredElementCollector(this.m_Revit.Application.ActiveUIDocument.Document).OfClass(typeof(Family)).ToElements())
			{
				Family family = element as Family;
				if (family != null)
				{
					Category familyCategory = RevitVersionFuncs.GetFamilyCategory(family);
					if (familyCategory != null && familyName.ToUpper().CompareTo(family.Name.ToUpper()) == 0)
					{
						foreach (FamilySymbol familySymbol in family.GetSymbols())
						{
							if (symbolName.ToUpper().CompareTo(familySymbol.Name.ToUpper()) == 0)
							{
								return familySymbol;
							}
						}
					}
				}
			}
			return result;
		}

		private ExternalCommandData m_Revit;

		private ElementId m_MaterialId;
	}
}
